package main

import (
	"encoding/binary"
	"fmt"
	"math"
)

type ColumnDefinition struct {
	Schema       string
	Table        string
	OrgTable     string
	Name         string
	OrgName      string
	CharacterSet uint16
	ColumnLength uint32
	ColumnType   byte
	Flags        uint16
	Decimals     byte
}

func (mr *monitoredConnection) handleFieldPacket(packet []byte) {
	field, err := parseFieldPacket(packet)
	if err != nil {
		// fmt.Println("解析字段定义包失败:", err)
		return
	}
	mr.currentResult.Columns = append(mr.currentResult.Columns, field)

}

func (mr *monitoredConnection) handleRowPacket(packet []byte) {
	if mr.currentState != 1 {
		return
	}
	row, err := parseRowPacket(packet, mr.currentResult.Columns)
	if err != nil {

		fmt.Println("解析数据行包失败:", err)
		return
	}
	mr.currentResult.Rows = append(mr.currentResult.Rows, row)
}

func (mr *monitoredConnection) handleEOFOrOKPacket(packet []byte) {
	if len(packet) < 5 {
		fmt.Println("无效的EOF或OK包")
		return
	}

	// 检查是否为OK包（MySQL 5.7.5及更高版本可能会发送OK包而不是EOF包）
	isOK := packet[0] == 0x00 && len(packet) >= 7

	// 检查是否为EOF包
	isEOF := packet[0] == 0xfe && len(packet) < 9

	if isOK {
		// 处理OK包
		mr.handleOKPacket(packet)
	} else if isEOF {
		// 处理EOF包
		mr.handleEOFPacket(packet)
	} else {
		fmt.Println("未知的包类型")
	}
}

func (mr *monitoredConnection) handleOKPacket(packet []byte) {
	// 处理OK包逻辑
	affectedRows := packet[1]
	lastInsertID := packet[2]
	mr.currentResult.AffectedRows = int64(affectedRows)
	mr.currentResult.LastInsertID = int64(lastInsertID)
	mr.addSqlResult()
	// mr.currentSQL = ""

}

func (mr *monitoredConnection) handleEOFPacket(packet []byte) {
	// 处理EOF包逻辑3
	statusFlags := binary.LittleEndian.Uint16(packet[3:5])
	if statusFlags&0x0008 == 0 {
		if mr.currentState == 0 {
			mr.currentState = 1
		} else if mr.currentState == 1 {
			mr.addSqlResult()
		}
		// SERVER_MORE_RESULTS_EXISTS 标志未设置，表示结果集传输完成
		// mr.addSqlResult()
		// mr.currentSQL = ""
	}
}

func parseFieldPacket(packet []byte) (ColumnDefinition, error) {
	var field ColumnDefinition
	var pos int

	field.Schema, pos = getLengthEncodedString(packet, 0)
	field.Table, pos = getLengthEncodedString(packet, pos)
	field.OrgTable, pos = getLengthEncodedString(packet, pos)
	field.Name, pos = getLengthEncodedString(packet, pos)
	field.OrgName, pos = getLengthEncodedString(packet, pos)

	if len(packet) < pos+13 {
		return field, fmt.Errorf("字段定义包数据不足")
	}

	pos++ // 跳过0x0C
	field.CharacterSet = binary.LittleEndian.Uint16(packet[pos:])
	pos += 2
	field.ColumnLength = binary.LittleEndian.Uint32(packet[pos:])
	pos += 4
	field.ColumnType = packet[pos]
	pos++
	field.Flags = binary.LittleEndian.Uint16(packet[pos:])
	pos += 2
	field.Decimals = packet[pos]

	return field, nil
}

func parseRowPacket(packet []byte, columns []ColumnDefinition) ([]interface{}, error) {
	var row []interface{}
	pos := 0

	for _, col := range columns {
		if pos >= len(packet) {
			return nil, fmt.Errorf("数据包长度不足")
		}

		if packet[pos] == 0xfb {
			row = append(row, nil)
			pos++
			continue
		}

		value, bytesRead, err := parseMySQLValue(packet[pos:], col)
		if err != nil {
			return nil, err
		}
		row = append(row, value)
		pos += bytesRead
	}

	return row, nil
}

func parseMySQLValue(data []byte, col ColumnDefinition) (interface{}, int, error) {
	length, numBytes := getLengthEncodedInteger(data)
	if numBytes == 0 {
		return nil, 0, fmt.Errorf("无效的长度编码整数")
	}

	if int(length)+numBytes > len(data) {
		return nil, 0, fmt.Errorf("数据包长度不足")
	}

	value := data[numBytes : numBytes+int(length)]

	switch col.ColumnType {
	case 0x01, 0x02, 0x03, 0x08: // TINY, SHORT, LONG, LONGLONG
		return parseIntegerValue(value, col.ColumnType)
	case 0x04, 0x05: // FLOAT, DOUBLE
		return parseFloatValue(value, col.ColumnType)
	case 0x0f, 0xfe: // VARCHAR, STRING
		return string(value), numBytes + int(length), nil
	// 可以根据需要添加更多类型的处理
	default:
		return string(value), numBytes + int(length), nil
	}
}

func parseIntegerValue(data []byte, columnType byte) (interface{}, int, error) {
	switch columnType {
	case 0x01: // TINY
		return int8(data[0]), 1, nil
	case 0x02: // SHORT
		return int16(binary.LittleEndian.Uint16(data)), 2, nil
	case 0x03: // LONG
		return int32(binary.LittleEndian.Uint32(data)), 4, nil
	case 0x08: // LONGLONG
		return int64(binary.LittleEndian.Uint64(data)), 8, nil
	default:
		return nil, 0, fmt.Errorf("未知的整数类型")
	}
}

func parseFloatValue(data []byte, columnType byte) (interface{}, int, error) {
	switch columnType {
	case 0x04: // FLOAT
		bits := binary.LittleEndian.Uint32(data)
		return math.Float32frombits(bits), 4, nil
	case 0x05: // DOUBLE
		bits := binary.LittleEndian.Uint64(data)
		return math.Float64frombits(bits), 8, nil
	default:
		return nil, 0, fmt.Errorf("未知的浮点类型")
	}
}

func getLengthEncodedInteger(data []byte) (uint64, int) {
	if len(data) == 0 {
		return 0, 0
	}
	switch data[0] {
	case 0xfc:
		if len(data) < 3 {
			return 0, 0
		}
		return uint64(data[1]) | uint64(data[2])<<8, 3
	case 0xfd:
		if len(data) < 4 {
			return 0, 0
		}
		return uint64(data[1]) | uint64(data[2])<<8 | uint64(data[3])<<16, 4
	case 0xfe:
		if len(data) < 9 {
			return 0, 0
		}
		return binary.LittleEndian.Uint64(data[1:]), 9
	default:
		return uint64(data[0]), 1
	}
}

func getLengthEncodedString(data []byte, start int) (string, int) {
	length, numBytes := getLengthEncodedInteger(data[start:])
	if numBytes == 0 {
		return "", start
	}
	end := start + numBytes + int(length)
	if end > len(data) {
		return "", start
	}
	return string(data[start+numBytes : end]), end
}

func getColumnTypeName(columnType byte) string {
	switch columnType {
	case 0x00:
		return "DECIMAL"
	case 0x01:
		return "TINY"
	case 0x02:
		return "SHORT"
	case 0x03:
		return "LONG"
	case 0x04:
		return "FLOAT"
	case 0x05:
		return "DOUBLE"
	case 0x06:
		return "NULL"
	case 0x07:
		return "TIMESTAMP"
	case 0x08:
		return "LONGLONG"
	case 0x09:
		return "INT24"
	case 0x0a:
		return "DATE"
	case 0x0b:
		return "TIME"
	case 0x0c:
		return "DATETIME"
	case 0x0d:
		return "YEAR"
	case 0x0e:
		return "NEWDATE"
	case 0x0f:
		return "VARCHAR"
	case 0x10:
		return "BIT"
	case 0xf6:
		return "NEWDECIMAL"
	case 0xf7:
		return "ENUM"
	case 0xf8:
		return "SET"
	case 0xf9:
		return "TINY_BLOB"
	case 0xfa:
		return "MEDIUM_BLOB"
	case 0xfb:
		return "LONG_BLOB"
	case 0xfc:
		return "BLOB"
	case 0xfd:
		return "VAR_STRING"
	case 0xfe:
		return "STRING"
	case 0xff:
		return "GEOMETRY"
	default:
		return fmt.Sprintf("UNKNOWN(%d)", columnType)
	}
}
